import time

from rctk.compat import json
from rctk.toolkit import Toolkit
from rctk.sessions import Session
from rctk.widgets.button import Button
from rctk.widgets.window import Window

##
## How about (shared) resource management?
## How about global state?
## How about js (resource) headers etc?

class Desktop(Session):
    """
        This combines both an RCTK application and a Session,
        which can multiplex across a number of subsessions as well,
        each holding an app instance by itself

        In the client however, we're one single, large application.
        I.e. no multiple Onion instances

        Each app gets assigned an application id, 0 is reserved for 
        the Desktop application itself. Intercept tasks and rewrite 
        control/timerids
    """
    def __init__(self, classid, args, kw, startupdir):
        super(Desktop, self).__init__(self, args, kw, startupdir)
        self.apps = {}
        self.counter = 1
        self.controlcounter = 1
        self.startupdir = startupdir
        ## map a control to an (appid, control)
        self._e2i = {0:(0, 0)}
        self._i2e = {(0, 0):0}
        self.queue = []

    def i2e(self, app, i):
        if (app, i) not in self._i2e:
            self._i2e[(app, i)] = self.controlcounter
            self._e2i[self.controlcounter] = (app, i)
            self.controlcounter += 1
        return self._i2e[(app, i)]

    def e2i(self, e):
        res = self._e2i.get(e)
        return res
        
    def handle(self, method, **arguments):
        if method == "start":
            ## possible resume!
            return self.tk.handle(method, **arguments)
        if method == "task" and 'queue' in arguments:
            queues = {}
            queue = json.loads(arguments['queue'])
            for task in queue:
                app, id = self.e2i(task['id'])

                task['id'] = id

                if app not in queues:
                    queues[app] = []
                queues[app].append(task)
            for app, q in queues.iteritems():
                serialized = json.dumps(q)
                if app == 0:
                    res = self.tk.handle(method, queue=serialized)
                    self.queue[0:0] = [(0, x) for x in res]
                else:
                    ## rewrite root back!
                    s, r = self.apps[app]
                    res = s.tk.handle(method, queue=serialized)
                    self.queue.extend((app, x) for x in res)
        else: ## just collect tasks
            for (app, (s, r)) in self.apps.items():
                res = s.tk.handle(method, **arguments)
                self.queue.extend((app, x) for x in res)
            res = self.tk.handle(method, **arguments)
            self.queue.extend((0, x) for x in res)


        result = []
        for app, task in self.queue:
            ## re-map root for everything but desktop app (app=0)
            if task['id'] == 0 and app != 0:
                s, r = self.apps[app]
                newroot = self.i2e(0, r.id)
                task['id'] = newroot
            else:
                task['id'] = self.i2e(app, task['id'])
            result.append(task)
        self.queue = []
        return result
    
    def serve(self, name):
        ## assume for now that the mainapp can handle the request.
        ## This won't be true for images! We need to be able to properly
        ## forward this as well!
        return self.tk.serve(name)

    def start_app(self,  classid):
        appid = self.counter
        self.counter += 1

        s = Session(classid, [], {}, self.startupdir)
        r = Window(self.tk,  classid)

        self.apps[appid] = (s, r)

        extern_window_id = self.i2e(0, r.id)

        self._i2e[(appid, 0)] = extern_window_id
        # self._e2i[extern_window_id] = (appid, 0)

        return appid
        
    def start_demos(self, event):
        appid = self.start_app("rctkdemos.controls_button.Standalone")
        s, r = self.apps[appid]
        s.tk.handle("start")
        res = s.tk.handle("pop")
        self.queue.extend((appid, x) for x in res)
        

    def start_events(self, event):
        appid = self.start_app("rctkdemos.events_timer.Standalone")
        s, r = self.apps[appid]
        s.tk.handle("start")
        res = s.tk.handle("pop")
        self.queue.extend((appid, x) for x in res)

    def start_tsjilp(self, event):
        appid = self.start_app("tsjilp.main.Tsjilp")
        s, r = self.apps[appid]
        s.tk.handle("start")
        res = s.tk.handle("pop")
        self.queue.extend((appid, x) for x in res)

    def run(self, tk):
        root = tk.root()
        b1 = Button(tk, "Button")
        b2 = Button(tk, "Timer")
        #b3 = Button(tk, "Tsjilp")

        b1.click = self.start_demos
        b2.click = self.start_events
        #b3.click = self.start_tsjilp

        root.append(b1)
        root.append(b2)
        #root.append(b3)
        root.layout()

    def __call__(self, *a, **kw):
        return self


